﻿using System;
using System.Linq;

namespace N2.Workflow
{
	using Items;
	/// <summary>
	/// Find a workflow definition for Content Items
	/// </summary>
	sealed class WorkflowDefinitionFinder
	{
		#region Fields

		readonly WorkflowRepository m_repo;

		#endregion Fields

		#region Constructor

		public WorkflowDefinitionFinder(WorkflowRepository repository)
		{
			this.m_repo = repository;
		}

		#endregion Constructor

		#region Public methods
		/// <summary>
		/// Take different strategies to obtain a workflow definition for a given item
		/// </summary>
		public Workflow FindWorkflow(ContentItem item)
		{
			return
				this.FindInParent(item)
				?? this.FindInRepositoryByContainer(item)
				?? this.FindInRepositoryByType(item);
		}

		#endregion Public methods

		#region Internal methods

		Workflow FindInParent(ContentItem item)
		{
			var _workflowContainer = Find.EnumerateParents(item).OfType<IWorkflowResolver>().FirstOrDefault();

			return null != _workflowContainer
				? _workflowContainer.Workflow
				: null;
		}

		Workflow FindInRepositoryByContainer(ContentItem item)
		{
			return this.m_repo.Items
				.OfType<WorkflowBindingByContainer>()
				.Where(_b => _b.Container.ID == item.Parent.ID)
				.Select(_b => _b.Workflow)
				.LastOrDefault();
		}

		Workflow FindInRepositoryByType(ContentItem item)
		{
			Type _type = item.GetType();
			
			return this.m_repo.Items
				.OfType<WorkflowBindingByType>()
				.Select(_b => Context.Persister.Get<WorkflowBindingByType>(_b.ID))
				.Where(_b => _b.ItemType == _type)
				.Select(_b => _b.Workflow)
				.LastOrDefault();
		}

		#endregion Internal methods
	}
}
